package submarines.logic;

import java.awt.Point;
import java.io.Serializable;
import java.util.Hashtable;
import java.util.LinkedList;

import submarines.logic.Submarine.eDirection;
import submarines.logic.interfaces.IGrid;

/**
 * @author Alon
 * 
 */
public class Grid implements IGrid, Comparable, Serializable
{
	private static final long serialVersionUID = 5088424913261396345L;
	private final int GRID_HEIGHT = 10;
	private final int GRID_WIDTH = 10;

	private final Point dimensions = new Point(GRID_WIDTH, GRID_HEIGHT);
	private Hashtable<Square, Submarine> submarines = new Hashtable<Square, Submarine>();

	@Override
	public Point getDimensions()
	{
		return dimensions;
	}

	/**
	 * @param square
	 *            : The top left square the submarine will lay in
	 * @param submarine
	 *            : The submarine to try and position on the grid
	 */
	@Override
	public boolean trySetSubmarine(Square square, Submarine submarine)
	{
		if (isSubmarineOutOfBoundries(square, submarine))
		{
			return false;
		}

		LinkedList<Square> targetSquares = new LinkedList<Square>();
		for (int i = 0; i < submarine.getLength(); ++i)
		{
			Square targetSquare = (Square) square.clone();

			if (submarine.getDirection() == eDirection.Horizontal)
			{
				targetSquare.x = square.x + i;
			}
			else if (submarine.getDirection() == eDirection.Vertical)
			{
				targetSquare.y = square.y + i;
			}

			if (submarines.containsKey(targetSquare))
			{
				return false;
			}

			targetSquares.add(targetSquare);
		}

		for (Square targetSquare : targetSquares)
		{
			submarines.put(targetSquare, submarine);
		}
		return true;
	}

	private boolean isSubmarineOutOfBoundries(Square square, Submarine submarine)
	{
		return (submarine.getDirection() == eDirection.Horizontal && square.x
				+ submarine.getLength() > GRID_WIDTH)
				|| (submarine.getDirection() == eDirection.Vertical && square.y
						+ submarine.getLength() > GRID_HEIGHT);
	}

	@Override
	public boolean bomb(Square square)
	{
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void select(Square square)
	{
		// TODO Auto-generated method stub

	}

	private boolean isSubmarineAt(Square square)
	{
		return this.submarines.containsKey(square);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + this.GRID_HEIGHT;
		result = prime * result + this.GRID_WIDTH;
		result = prime * result
				+ ((this.dimensions == null) ? 0 : this.dimensions.hashCode());
		result = prime * result
				+ ((this.submarines == null) ? 0 : this.submarines.hashCode());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
		{
			return true;
		}
		if (obj == null)
		{
			return false;
		}
		if (getClass() != obj.getClass())
		{
			return false;
		}
		Grid other = (Grid) obj;
		if (this.GRID_HEIGHT != other.GRID_HEIGHT)
		{
			return false;
		}
		if (this.GRID_WIDTH != other.GRID_WIDTH)
		{
			return false;
		}
		if (this.dimensions == null)
		{
			if (other.dimensions != null)
			{
				return false;
			}
		}
		else if (!this.dimensions.equals(other.dimensions))
		{
			return false;
		}
		if (this.submarines == null)
		{
			if (other.submarines != null)
			{
				return false;
			}
		}
		else if (!this.submarines.equals(other.submarines))
		{
			return false;
		}
		return true;
	}

}
